package com.gitee.ixtf.vertx.internal.internal

import graphql.execution.instrumentation.InstrumentationState
import graphql.execution.instrumentation.SimplePerformantInstrumentation
import graphql.execution.instrumentation.parameters.InstrumentationFieldFetchParameters
import graphql.schema.*
import io.vertx.core.json.JsonObject
import java.util.function.Supplier

object JsonObjectAdapterInstrumentation : SimplePerformantInstrumentation() {
  private val FOR_SINGLETON_FETCHER = JsonObjectCompatible(SingletonPropertyDataFetcher.singleton())

  override fun instrumentDataFetcher(
      dataFetcher: DataFetcher<*>,
      parameters: InstrumentationFieldFetchParameters,
      state: InstrumentationState?
  ): DataFetcher<*> =
      when (dataFetcher) {
        is SingletonPropertyDataFetcher<*> -> FOR_SINGLETON_FETCHER
        is PropertyDataFetcher<*> -> JsonObjectCompatible(dataFetcher)
        else -> dataFetcher
      }

  private class JsonObjectCompatible(private val delegate: LightDataFetcher<*>) :
      LightDataFetcher<Any?> {
    override fun get(
        fieldDefinition: GraphQLFieldDefinition?,
        sourceObject: Any?,
        environmentSupplier: Supplier<DataFetchingEnvironment?>?
    ): Any? =
        if (sourceObject is JsonObject)
            delegate.get(fieldDefinition, sourceObject.map, environmentSupplier)
        else delegate.get(fieldDefinition, sourceObject, environmentSupplier)

    override fun get(environment: DataFetchingEnvironment?) =
        get(environment?.fieldDefinition, environment?.getSource()) { environment }
  }
}
